#include "c_defines.h"
#include "glut_win.h"
#include "shader_mgr.h"
#include <glm/ext.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>

using namespace std;

void Init(void)
{
    glClearColor(.22f, .21f, .23f, 0.f);

    // 开启点的平滑减少锯齿
    glEnable(GL_POINT_SMOOTH);
    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);

    // 启用线的反走样
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND); // 混合与线的平滑需要同时启用，减少锯齿
    glBlendFunc(GL_ONE, GL_ONE_MINUS_DST_ALPHA);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_MULTISAMPLE);

    auto shader = CShaderManager::GetInstance().CreateNewShader("line");
    shader->LoadShader("../shader/line.vert", "../shader/line.frag", 2, 0, "vVertexs", 1, "vColor");
}

/**
 * @brief 画直线
 * @note 通过glVertexPointer定义一个数组,
 */
void Display()
{
    static auto shader = CShaderManager::GetInstance().GetShader("line");

    // 获取着色器属性
    // static auto projLoc = glGetUniformLocation(shader, "projection");
    // static auto viewLoc = glGetUniformLocation(shader, "view");
    // static auto modelLoc = glGetUniformLocation(shader, "model");
    // static auto colorLoc = glGetUniformLocation(shader, "color");

    static glm::mat4 projection = glm::perspective(glm::radians(75.f), GLfloat(640) / GLfloat(480), 1.f, 100000.f);
    static glm::mat4 view = glm::lookAt(glm::vec3(0.f, 15.f, -10.f), glm::vec3(0.f), glm::vec3(0.f, 1000.f, -10.f));
    static glm::mat4 model = glm::scale(glm::mat4(1.f), glm::vec3(1.f));

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    shader->Enable();
    // 设置属性值
    shader->SetUniformMatrix4fv("projection", glm::value_ptr(projection));
    shader->SetUniformMatrix4fv("view", glm::value_ptr(view));
    shader->SetUniformMatrix4fv("model", glm::value_ptr(model));

    GLfloat color[] = {1.0f, 0.f, 1.f};
    shader->SetUniform3fv("color", color);

    GLfloat verteics[] = {-2.f, 0.f, -2.f, 2.f, 0.f, -2.f, -2.f, 0.f, 2.f, 2.f, 0.f, 2.f};

    // 启用数组
    glEnableClientState(GL_VERTEX_ARRAY);
    // glColor3fv(color);

    /**
     * @brief 定义顶点数组
     * @param [in] size 指定每个顶点的坐标个数
     * @param [in] type 指定每个顶点的数据类型
     * @param [in] stride 指定连续顶点的字节排列方式,顶点坐标间的间隔
     * @param [in] pointer 数组中第一个顶点的首地址
     */
    glVertexPointer(3, GL_FLOAT, 0, verteics);

    /**
     * @brief 使用启用数组中的顺序元素来构造形状
     * @param [in] mode 绘制基元类型
     * @param [in] first 启用数组的顶点序列的起始索引
     * @param [in] count 要绘制的顶点数量
     */
    glDrawArrays(GL_LINES, 0, 4);

    // 禁用数组
    glDisableClientState(GL_VERTEX_ARRAY);

    shader->Disable();

    glFinish();
}

int main(int argc, char **argv)
{
    CGlutWindow window("shader test");

    window.Init(&argc, argv);

    Init();

    window.RegisterCallbackFunc([]() {
        glutDisplayFunc(Display);
        glutIdleFunc(Display);
    });

    window.MainLoop();

    return 0;
}